%{ open Ast %}

%token PLUS MINUS TIMES DIVIDE FPLUS FMINUS FTIMES FDIVIDE ASSIGN LPAREN RPAREN LBRACE RBRACE COMMA SEMI INT STRINGV DQUOTATION SQUOTATION LSQUA RSQUA PERIOD RETURN FLO EOF 
%token <int> LITERAL
%token <float> FLOAT
%token <string> ID
%token <string> STR
%token <char> CHAR


%left PLUS MINUS
%left TIMES DIVIDE

%start program
%type < Ast.expr> expr
%type < Ast.stmt> stmt
%type < Ast.func> fdel
%type < Ast.program> program

%%

expr:
  LPAREN expr PLUS   expr RPAREN { Binop($2, Add, $4) }
| LPAREN expr MINUS  expr RPAREN { Binop($2, Sub, $4) }
| LPAREN expr TIMES  expr RPAREN { Binop($2, Mul, $4) }
| LPAREN expr DIVIDE expr RPAREN { Binop($2, Div, $4) }
| LPAREN expr FPLUS   expr RPAREN { FBinop($2, Fadd, $4) }
| LPAREN expr FMINUS  expr RPAREN { FBinop($2, Fsub, $4) }
| LPAREN expr FTIMES  expr RPAREN { FBinop($2, Fmul, $4) }
| LPAREN expr FDIVIDE expr RPAREN { FBinop($2, Fdiv, $4) }
| LITERAL          { Lit($1) }
| FLOAT            { Float($1)}
| ID               { Id($1)} 
| CHAR             { Char($1)}
| STR              { Str($1)}
| ID LPAREN actuals_opt RPAREN {Call($1,$3)}
| INT ID           {Int($2)}
| FLO ID           {Flo($2)}
| STRINGV ID        {Stringv($2)}
| ID ASSIGN expr   {Assign($1,$3)}
| INT ID LSQUA LITERAL RSQUA {IntArray($2,$4)}
| ID LSQUA LITERAL RSQUA ASSIGN expr {ArrAssign($1,$3,$6)}
| RETURN expr      {Return($2)}



stmt:
  expr SEMI        {Expr($1)}
| LBRACE stmt_list RBRACE        {Block(List.rev $2)}

program:
                   {[]}
| program fdel     {$2::$1}

fdel:
 ID LPAREN formals_opt RPAREN LBRACE stmt_list RBRACE
{{ fname=$1; formals=$3; body=Block(List.rev $6); }}

formals_opt:
                   {[]}
 | formal_list     {List.rev $1}

formal_list:
  var               {[$1]}
| formal_list COMMA var {$3::$1} 

var:
  INT ID                {$2}
| STRINGV ID            {$2}
| FLO ID                {$2}


stmt_list:
                   {[]}
|  stmt_list stmt   {$2::$1}

actuals_list:
  expr         {[$1]}
| actuals_list COMMA expr {$3 :: $1}

actuals_opt:
               {[]}
| actuals_list {List.rev $1}




